/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Hardware_Accelerated;

import Utilities.ImageCollection;
import Utilities.InputAdvance;
import Utilities.KeyBoard;
import Utilities.Mouse;
import Utilities.Vector2;
import Utilities.ViewScreen;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.image.BufferStrategy;

/**
 *
 * @author KyleSweeney
 */
public abstract class AGame implements Runnable{
    /**
     * The Keyboard object belonging to the game object.
     */
    public KeyBoard keyboard;
    /**
     * The Mouse object belonging to the game object.
     */
    public Mouse mouse;
    private ImageCollection batch;
    private boolean isRunning;
    private InputAdvance inputs;
    /**
     * The Amount of milliseconds between the runtime of thread.
     */
    public static int FPS_DELAY=16;
    /**
     * The width of the game window. If you change this, you need to do it in the resize method.
     */
    public int GAME_WIDTH=800;
    /**
     * The height of the game window. If you change this, you need to do it in the resize method.
     */
    public int GAME_HEIGHT=600;
    /**
     * The Viewscreen. This is the game window into the game world. If you move this, you change the entire view.
     */
    public ViewScreen v;
    
    private Color bgc=Color.white;
    
    private BufferStrategy gfx;
    
    private long internalClock;
    
    
    public AGame(){
        keyboard=new KeyBoard();
        mouse=Mouse.getCurrentInstance();
        internalClock=System.currentTimeMillis();
        inputs= new Inputs();
        v=new ViewScreen(new Vector2(GAME_WIDTH, GAME_HEIGHT));
        batch=new ImageCollection(v);
        isRunning=true;
        InitializeAndLoad();
        
    }
    
    public abstract void InitializeAndLoad();
    /**
     * Seriously, does anyone know what this does? It will be called when you call exit()
     *@deprecated
     */
    public abstract void UnloadContent();
    
    public abstract void Update();
    public abstract void Draw(Graphics2D g, ImageCollection batch);
    
    public void exit(){
        UnloadContent();
        isRunning=false;
        System.exit(0);
    }
    
    public void giveGraphics(BufferStrategy gfx){
        this.gfx=gfx;
    }
    
    public InputAdvance getInputs(){
        return inputs;
    }
    
    public void setBackgroundColor(Color c){
        bgc=c;
    }
    
    public void resize(int width, int height){
        this.GAME_HEIGHT=height;
        this.GAME_WIDTH=width;
        this.v.setHeight(height);
        this.v.setWidth(width);
        AccelGame.frame.setVisible(false);
        AccelGame.frame.setSize(width, height);
        AccelGame.frame.setVisible(true);
    }
    
    private void updateGUI(BufferStrategy strategy){
        Graphics2D gfx = (Graphics2D) strategy.getDrawGraphics();
        gfx.setColor(bgc);
        gfx.fillRect(0,0,AccelGame.gui.getWidth(), AccelGame.gui.getHeight());
        Draw(gfx,batch);
        batch.Render(gfx, AccelGame.gui);
        gfx.dispose();
        strategy.show();
    }
    
    @Override
    public void run(){
        internalClock=System.currentTimeMillis();
        synchronized(this){
            while(isRunning){
                internalClock=System.currentTimeMillis();
                //game logic
                Update();
                //graphics
                updateGUI(AccelGame.gui.getBufferStrategy());
                
                //inputfix?
                //AccelGame.gui.setFocusable(true);
                
                //sleeping
                //internalClock+=FPS_DELAY;
                long difference =System.currentTimeMillis()-internalClock;
                try{
//                    Thread.sleep(Math.max(0, difference));
                    //System.out.println("Difference: "+difference);
                    if(difference > FPS_DELAY){
                        continue;
                    }else{
                        long sleep=FPS_DELAY-difference;
                        Thread.sleep(sleep);
                    }
                    //Thread.sleep(Math.min(difference, FPS_DELAY));
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
        }
    }
    
    public boolean isAlive(){
        return isRunning;
    }
   
    
        // <editor-fold defaultstate="collapsed" desc="InputClass">
    /**
     * the class which handles all input events
     */
    protected class Inputs extends InputAdvance{

        @Override
        public void keyTyped(KeyEvent e) {
        }

        @Override
        public void keyPressed(KeyEvent e) {
            keyboard.setPressed(e);
        }

        @Override
        public void keyReleased(KeyEvent e) {
            keyboard.setRelease(e);
        }

        @Override
        public void mouseClicked(MouseEvent e) {
        }

        @Override
        public void mousePressed(MouseEvent e) {
            mouse.setButton(e);
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            mouse.setRelease(e);
        }

        @Override
        public void mouseEntered(MouseEvent e) {
            mouse.mouseMoved(e);
        }

        @Override
        public void mouseExited(MouseEvent e) {
            mouse.mouseMoved(e);
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            mouse.mouseMoved(e);
        }

        @Override
        public void mouseMoved(MouseEvent e) {
            mouse.mouseMoved(e);
        }

        @Override
        public void mouseWheelMoved(MouseWheelEvent e) {
            mouse.mouseScroll(e);
        }

    }
    // </editor-fold>
}
